// Ŭnicode please
#include <string>
#include <map>

#include "SRGLinc.h"
#include "SRResource.h"
#include "SRPlatform.h"

using std::string;
using std::map;

namespace sora
{
	Texture::Texture()
	{
		glGenTextures(1, &texId_);
	}
	Texture::~Texture()
	{
		TextureManager::mgr().unloadOccur(texId());
		//텍스쳐 소멸작업 수행후 tex mgr에 texId가 바뀌었음을 알린다
		glDeleteTextures(1, &texId_);
	}
	GLuint Texture::texId() const { return texId_; }


	SampleTexture::SampleTexture()
		: Texture()
	{
		const int texSize = 128;
		
		GLuint* pTexData = new GLuint[texSize*texSize];

		for(int i = 0; i < texSize; ++i)
		{
			for(int j = 0; j < texSize; ++j)
			{
				// Fills the data with a fancy pattern
				GLuint col = (255L<<24) + ((255L-j*2)<<16) + ((255L-i)<<8) + (255L-i*2);

				if( ((i*j)/8) % 2 )
					col = 0xffff00ff;

				pTexData[j*texSize+i] = col;
			}
		}
		
		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texSize, texSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, pTexData);
		glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
		glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );

		//Deletes the texture data, it's now in OpenGL memory
		delete[] pTexData;
	}
	SampleTexture::~SampleTexture()
	{
	}

	TextureManager::TextureManager()
	{
	}
	TextureManager::~TextureManager()
	{
		map<GLuint, Texture*>::iterator it;
		for(it = texMap_.begin() ; it != texMap_.end() ; it++)
		{
			delete(it->second);
		}
	}
	TextureManager &TextureManager::mgr()
	{
		static TextureManager m;
		return m;
	}

	void TextureManager::unloadOccur(GLuint texId)
	{
		map<GLuint, Texture*>::iterator it = texMap_.find(texId);
		if(it != texMap_.end())
			texMap_.erase(it);
	}

	Texture *TextureManager::get(GLuint texId) const
	{
		map<GLuint, Texture*>::const_iterator it = texMap_.find(texId);
		Texture *tex = it->second;
		assert(tex != NULL);
		return tex;
	}

	BufferObjectManager::BufferObjectManager()
	{
	}
	BufferObjectManager &BufferObjectManager::mgr()
	{
		static BufferObjectManager m;
		return m;
	}
	BufferObjectManager::~BufferObjectManager()
	{
	}

	VertexBufferObject::VertexBufferObject(const GLvoid *data, int count, GLsizei stride, GLenum usage)
	: buffer_(0), count_(count), stride_(stride)
	{
		glGenBuffers(1, &buffer_);
		glBindBuffer(GL_ARRAY_BUFFER, buffer_);
		glBufferData(GL_ARRAY_BUFFER, stride*count, data, usage);
	}
	VertexBufferObject::VertexBufferObject(const DrawCommand &cmd, GLenum usage)
		: buffer_(0), count_(0), stride_(0)
	{
		stride_ = cmd.pointer().stride();
		count_ = cmd.pointer().count();
		glGenBuffers(1, &buffer_);
		glBindBuffer(GL_ARRAY_BUFFER, buffer_);
		glBufferData(GL_ARRAY_BUFFER, stride_*count_, cmd.pointer().start(), usage);
	}
	VertexBufferObject::~VertexBufferObject()
	{
		glDeleteBuffers(1, &buffer_);
	}

	IndexBufferObject::IndexBufferObject(const GLvoid *data, int count, GLenum indexType, GLenum drawMode, GLenum usage)
	: buffer_(0), count_(count), drawMode_(drawMode), indexType_(indexType)
	{
		//stride 계산
		switch (indexType) {
			case GL_UNSIGNED_BYTE:
				stride_ = sizeof(GLubyte);
				break;
			case GL_UNSIGNED_SHORT:
				stride_ = sizeof(GLushort);
				break;
			default:
				assert(!"Not valid indexType");
				break;
		}
		glGenBuffers(1, &buffer_);
		glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer_);
		glBufferData(GL_ELEMENT_ARRAY_BUFFER, stride_*count, data, usage);
	}

	IndexBufferObject::IndexBufferObject(const DrawCommand &cmd, GLenum usage)
		: buffer_(0), count_(cmd.count()), drawMode_(cmd.mode()), indexType_(GL_UNSIGNED_SHORT)
	{
		stride_ = sizeof(GLushort);
		glGenBuffers(1, &buffer_);
		glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer_);
		glBufferData(GL_ELEMENT_ARRAY_BUFFER, stride_*cmd.count(), cmd.indices(), usage);
		
	}
	IndexBufferObject::~IndexBufferObject()
	{
		glDeleteBuffers(1, &buffer_);
	}
}

